package zhou.chs.p4_4;

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener,View.OnClickListener{
    private TextView tvRxd,tvSta;
    private EditText etTxd;
    private EditText etIP,etPort;
    private Spinner spS1,spS2,spS3;
    private Handler mHandler;
    private Socket mSocket;
    private ServerSocket sSocket;
    private DatagramSocket uSocket;
    private DatagramPacket rPacket,tPacket;
    boolean running = false;
    private Button btSend,btSave,btClear,btCRC;
    private Button btStart,btStop;

    private StartThread st;     //TCP客户端线程
    private ConnectedThread rt; //TCP数据交换线程
    private AcceptThread lt;    //TCP服务器端线程
    private UdpThread ut;       //UDP线程
    private ReceiveThread ct;   //UDP接收线程

    private String strRxd = "";        //接收端文本
    private String strTxd = "";    //发送端文本
    private byte rbuf[] = new byte[480];		//接收数据
    private int len;    //接收数据长度
    public boolean sp1=false;   //false：接收区为HEX模式，true：TEXT模式
    public boolean sp2=false;   //false：发送区为HEX模式，true：TEXT模式
    private int sp3=0;    //通信模式：0-udp  1-tcpClient   2-tcpServe

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //控件实例化
        tvRxd = (TextView) findViewById(R.id.idtv1);
        tvSta = (TextView) findViewById(R.id.idtv2);
        etTxd = (EditText) findViewById(R.id.idet1);
        etIP = (EditText) findViewById(R.id.idet2);
        etPort = (EditText) findViewById(R.id.idet3);
        spS1=(Spinner)findViewById(R.id.idS1);
        spS2=(Spinner)findViewById(R.id.idS2);
        spS3=(Spinner)findViewById(R.id.idS3);
        btSend = (Button) findViewById(R.id.idSend);
        btStart = (Button) findViewById(R.id.idConnect);
        btStop = (Button) findViewById(R.id.idStop);
        btSave = (Button) findViewById(R.id.idSave);
        btClear = (Button) findViewById(R.id.idClear);
        btCRC = (Button) findViewById(R.id.idCRC);
        //控件事件监听注册
        spS1.setOnItemSelectedListener(this);
        spS2.setOnItemSelectedListener(this);
        spS3.setOnItemSelectedListener(this);
        btSend.setOnClickListener(this);
        btStart.setOnClickListener(this);
        btStop.setOnClickListener(this);
        btSave.setOnClickListener(this);
        btClear.setOnClickListener(this);
        btCRC.setOnClickListener(this);
        mHandler = new MyHandler(); //实例化Handler，用于进程间的通信
        tvSta.setText("本地IP:" + getLocalIP());
        btSend.setEnabled(false); //发送按钮禁止操作
    }
    //按键监听处理
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.idClear:      //清空按钮
                strRxd="";
                tvRxd.setText("");
                break;
            case R.id.idSave:      //保存按钮
                File file = new File(this.getExternalFilesDir
                        (Environment.DIRECTORY_DOCUMENTS),"mydata.txt");
                try {               //将文本内容保存为文件
                    FileWriter fw = new FileWriter(file);
                    fw.write(tvRxd.getText().toString());
                    fw.close();
                } catch (Exception e) {
                }
                break;
            case R.id.idCRC:        //CRC按钮
                if(!sp2) {          //HEX模式才有效
                    String s=etTxd.getText().toString();
                    etTxd.setText(crc16(s));
                }
                break;
            case R.id.idConnect:    //连接按钮
                if(sp3==0){
                    ut = new UdpThread();
                    ut.start();  //进入UDP连接线程
                }
                if(sp3==1){
                    st = new StartThread();
                    st.start();  //进入TCP Client线程
                }
                if(sp3==2){
                    lt = new AcceptThread();
                    lt.start(); //进入TCP Server线程
                }
                break;
            case R.id.idSend:                   // 发送按钮
                strTxd = etTxd.getText().toString();
                len = strTxd.length();
                if(!sp2) {    //HEX模式
                    byte[] tbuf = new byte[len / 2];
                    for (int i = 0; i < len; i += 2) {
                        tbuf[i / 2] = (byte) ((Character.digit(strTxd.charAt(i), 16) << 4) + Character.digit(strTxd.charAt(i + 1), 16));
                    }
                    if(sp3==0){
                        tPacket = null;
                        try {
                            tPacket = new DatagramPacket(tbuf, len/2);
                            uSocket.send(tPacket);  //UDP连接发送数据
                        } catch (Exception e) {
                        }
                    }
                    else {
                        rt.write(tbuf);      //TCP连接发送数据
                    }
                }
                else{   //TEXT模式
                    if(sp3==0){
                        tPacket = null;
                        try {
                            tPacket = new DatagramPacket((etTxd.getText().toString() + "\n").getBytes("utf-8"), len);
                            uSocket.send(tPacket);  //UDP连接发送数据
                        } catch (Exception e) {

                        }
                    }
                    else {
                        try {           //TCP连接发送数据
                            rt.write((etTxd.getText().toString() + "\n").getBytes("utf-8"));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
                break;
            case R.id.idStop: //断开按钮
                running = false;
                btSend.setEnabled(false); //发送按钮禁止操作
                switch (sp3) {
                    case 0:
                        try {
                            uSocket.close();
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        }
                        break;
                    case 1:
                        try {
                            sSocket.close();
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        break;
                    case 3:
                        try {
                            mSocket.close();
                        } catch (NullPointerException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        break;
                }
                break;
        }
    }
    //下拉菜单的监听事件
    public void onItemSelected(AdapterView<?> patent,View view,int position,long id){
        switch (patent.getId()) {
            case R.id.idS1:  //接收区HEX与TEXT选择
                if (position == 0) sp1 = false;
                else sp1 = true;
                break;
            case R.id.idS2: //发送区HEX与TEXT选择
                if (position == 0) sp2 = false;
                else sp2 = true;
                break;
            case R.id.idS3: //通信模式选择
                tvSta.setText("本地IP：" + getLocalIP() + ",本地端口：6000");
                sp3 = position;
                if (sp3 == 2) {
                    etIP.setText("");
                    etPort.setText("");
                } else {
                    etIP.setText("192.168.0.101");
                    etPort.setText("8080");
                }
                break;
        }
    }
    public void onNothingSelected(AdapterView<?> patent){
        //定义未选择项目时的处理
    }
    // UDP连接线程
    private class UdpThread extends Thread{
        public void run() {
            try {
                uSocket = new DatagramSocket(6000);  //绑定本地端口为6000
                //建立UDP连接，参数为对侧IP地址和端口
                uSocket.connect(InetAddress.getByName(etIP.getText().toString()), Integer.parseInt(etPort.getText().toString()));
                ct = new ReceiveThread();
                ct.start();     //运行接收UDP数据线程
                running=true;
                Message msg = mHandler.obtainMessage();
                msg.what = 0;
                mHandler.sendMessage(msg);
            } catch (Exception e) {
            }
        }
    }
    // UDP数据接收线程
    private class ReceiveThread extends Thread{
        @Override
        public void run() {
            int byt; // bytes returned from read()
            while (running) {
                rPacket = null;
                try {
                    rPacket = new DatagramPacket(rbuf, rbuf.length);
                    uSocket.receive(rPacket);   //接收数据
                    byt=rPacket.getLength();
                    if(byt>0){    //收到数据
                        Message msg1 = mHandler.obtainMessage();
                        msg1.what = 1;
                        msg1.obj=byt;
                        mHandler.sendMessage(msg1); // 通知主线程接收到数据
                        try{
                            sleep(200);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                } catch (NullPointerException e) {
                    running = false;//防止服务器端关闭导致客户端读到空指针而导致程序崩溃
                    e.printStackTrace();
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    // TCP Client连接线程
    private class StartThread extends Thread{
        @Override
        public void run() {
            try {       //连接服务端的IP地址和端口
                mSocket = new Socket(etIP.getText().toString(), Integer.parseInt(etPort.getText().toString()));
                rt = new ConnectedThread(mSocket);//启动接收数据的线程
                rt.start();
                running = true;
                if(mSocket.isConnected()){           //成功连接获取socket对象则发送成功消息
                    Message msg0 = mHandler.obtainMessage();
                    msg0.what=0;
                    mHandler.sendMessage(msg0);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    //TCP Server监听线程
    private class AcceptThread extends Thread{
        @Override
        public void run() {
            try {
                sSocket = new ServerSocket(6000);  //建立一个ServerSocket服务器端
                Message msg4 = mHandler.obtainMessage();
                msg4.what = 4;
                mHandler.sendMessage(msg4);//返回连接成功的信息
                mSocket = sSocket.accept();          //阻塞直到有socket客户端连接
                rt = new ConnectedThread(mSocket);
                rt.start();
                running = true;
                try {
                    sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message msg3 = mHandler.obtainMessage();
                msg3.what = 3;
                msg3.obj = mSocket.getInetAddress().getHostAddress();//获取客户端IP地址
                mHandler.sendMessage(msg3);//返回连接成功的信息
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    // TCP数据传输线程
    private class ConnectedThread extends Thread {
        private final Socket mmSocket;
        private final InputStream mmInStream;
        private final OutputStream mmOutStream;
        public ConnectedThread(Socket socket) {   //socket连接
            mmSocket = socket;
            InputStream tmpIn = null;
            OutputStream tmpOut = null;
            try {
                tmpIn = mmSocket.getInputStream();      //数据通道创建
                tmpOut = mmSocket.getOutputStream();
                Message msg0 = mHandler.obtainMessage();
                msg0.what = 0;
                mHandler.sendMessage(msg0);
            } catch (IOException e) { }
            mmInStream = tmpIn;
            mmOutStream = tmpOut;
        }
        public final void run() {
            while (running) {
                int byt;
                try {
                    byt = mmInStream.read(rbuf);     // 监听接收到的数据
                    if(byt>0){
                        Message msg1 = mHandler.obtainMessage();
                        msg1.what = 1;
                        msg1.obj=byt;
                        mHandler.sendMessage(msg1); // 通知主线程接收到数据
                        try{
                            sleep(200);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                } catch (NullPointerException e) {
                    running = false;//防止服务器端关闭导致客户端读到空指针而导致程序崩溃
                    Message msg2 = mHandler.obtainMessage();
                    msg2.what = 2;
                    mHandler.sendMessage(msg2);//发送信息通知用户客户端已关闭
                    e.printStackTrace();
                    break;
                } catch (IOException e) {
                    break;
                }
            }
        }
        public void write(byte[] bytes) {       //发送字节数据
            try {
                mmOutStream.write(bytes);
            } catch (IOException e) { }
        }
        public void cancel() {      //关闭连接
            try {
                mmSocket.close();
            } catch (IOException e) { }
        }
    }
    //在主线程处理Handler传回来的message
    class  MyHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    tvSta.setText("连接成功");
                    btSend.setEnabled(true); //发送按钮使能
                    break;
                case 1:
                    tvSta.setText("收到数据");
                    len=Integer.parseInt(msg.obj.toString());
                    if(!sp1){
                        for(int i=0;i<len;i++){
                            strRxd = strRxd + String.format("%02X",rbuf[i]) + " ";
                        }
                    }
                    else{
                        for(int i=0;i<len;i++){
                            strRxd = strRxd + String.format("%c",rbuf[i]);
                        }
                    }
                    tvRxd.setText(strRxd);
                    break;
                case 2:
                    tvSta.setText("已断开");
                    //setButtonOnStartState(true);//设置按键状态为可开始
                    break;
                case 3:
                    etIP.setText(msg.obj.toString());
                    //setButtonOnStartState(false);//设置按键状态为可开始
                    break;
                case 4:
                    tvSta.setText("服务器已启动，等待客户端登录");
                    break;
            }
        }
    }
    //获取WiFi状态下的信息
    public String getLocalIP()
    {
        String ipstr = "";      // 本机在WIFI状态下路由分配给的IP地址
        // 获取wifi管理器
        WifiManager wifiMng = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        WifiInfo info = wifiMng.getConnectionInfo();
        //String mac = info.getMacAddress();// 获得本机的MAC地址
        //String ssid = info.getSSID();// 获得本机所链接的WIFI名称
        int ipadr = info.getIpAddress();
        if (ipadr != 0) {
            ipstr = ((ipadr & 0xff) + "." + (ipadr >> 8 & 0xff) + "."
                    + (ipadr >> 16 & 0xff) + "." + (ipadr >> 24 & 0xff));
        }
        return ipstr;
    }
    //CRC校验子程序
    public static StringBuffer crc16(String strtbuf) {
        strtbuf = strtbuf.replaceAll(" ", ""); //去掉字符串中的空格
        int n = strtbuf.length();
        String ad;
        int[] w=new int[n/2];
        for (int i = 0; i <n; i=i+2) {  //字符串转为16进制数据
            ad=strtbuf.substring(i,i+2);
            w[i/2]=Integer.parseInt(ad,16);
        }
        int[] data=w;
        int[] stem=new int[data.length+2];
        //CRC校验计算
        int a,b,c;
        a=0xFFFF;
        b=0xA001;
        for (int i = 0; i < data.length; i++) {
            a^=data[i];
            for (int j = 0; j < 8; j++) {
                c=(int)(a&0x01);
                a>>=1;
                if (c==1) {
                    a^=b;
                }
                System.arraycopy(data, 0, stem, 0, data.length);
                stem[stem.length-2]=(int)(a&0xFF);
                stem[stem.length-1]=(int)(a>>8);
            }
        }
        int[] z = stem;
        StringBuffer s = new StringBuffer();
        for (int j = 0; j < z.length; j++) {
            s.append(String.format("%02X", z[j]));
        }
        return s;  //返回带校验的字符串
    }
}
